package EA.operators.recombination;
import EA.*;
import RKUjava.math.*;

/** Arithmtic crossover on RealNumericalGenomes. This class implements four
    variants of the arithmetic crossover (see below).
*/
public class RNumArithmeticCrossover extends NumCrossover
{

  public RNumArithmeticCrossover()
    {
      super();
      crossovername = "arithmetic crossover";
    }


  /** Produce one offspring from two parents.
      @param parent1 The first parent.
      @param parent2 The second parent.
      @param params The parameters for the operator. 
      <ul>
      <li>First parameter: 
      <ul>
      <li>0 = offspring is created on the line between the parents. 
      This variant is used if null is passed as <tt>params</tt>.
      <li>1 = offspring is created in the hypercube defined by the 
      two parents (one weight per entry in realpos).
      </ul>
      </ul>
  */
  public static NumericalGenome crossover(NumericalGenome parent1, NumericalGenome parent2, double[] params) 
    {
      double w;
      int i;
      RealNumericalGenome offspring;
      RealNumericalGenome p1, p2;

      p1 = (RealNumericalGenome)parent1;
      p2 = (RealNumericalGenome)parent2;
	
      offspring = new RealNumericalGenome(parent1.framework,false);

      // On the line
      if (params==null || params[0]==0) {
	w = Math.random();

	for (i=0; i<offspring.realpos.length; i++) {
	  offspring.realpos[i] = w*p1.realpos[i] + (1-w)*p2.realpos[i];
	}
      }

      // In the hypercube
      else {
	for (i=0; i<offspring.realpos.length; i++) {
	  w = Math.random();
	  offspring.realpos[i] = w*p1.realpos[i] + (1-w)*p2.realpos[i];
	}
	    
      }
      return offspring;
    }

  /** Produce one offspring from N parents.
      @param parents The parents.
      @param params The parameters for the operator. 
      <ul>
      <li>First parameter: 
      <ul>
      <li>0 = offspring is created in the convex hull defined by parents. 
      This variant is used if null is passed as <tt>params</tt>.
      <li>1 = offspring is created in the hypercube defined by the 
      two parents (one weight per entry in realpos).
      </ul>
      </ul>
  */
  public static NumericalGenome crossover(NumericalGenome[] parents, double[] params) 
    {
      double[] w;
      int i, j;
      RealNumericalGenome offspring;
	
      offspring = new RealNumericalGenome(parents[0].framework,false);

      // On the line
      if (params==null || params[0]==0) {
	w = new double[parents.length];

	for (j=0; j<parents.length; j++) {
	  w[j] = Math.random();
	}
	RKUGeometry.normalizeVector(w);

	for (i=0; i<offspring.realpos.length; i++) {
	  offspring.realpos[i] = 0;
	  for (j=0; j<parents.length; j++) {
	    offspring.realpos[i] += w[j]*((RealNumericalGenome)parents[j]).realpos[i];
	  }
	}
      }

      // In the hypercube
      else {
	w = new double[parents.length];


	for (i=0; i<offspring.realpos.length; i++) {
	  for (j=0; j<parents.length; j++) {
	    w[j] = Math.random();
	  }
	  RKUGeometry.normalizeVector(w);

	  offspring.realpos[i] = 0;
	  for (j=0; j<parents.length; j++) {
	    offspring.realpos[i] += w[j]*((RealNumericalGenome)parents[j]).realpos[i];
	  }
	}
      }
      return offspring;
    }



  /** Produce an array offspring from two parents.
      @param parent1 The first parent.
      @param parent2 The second parent.
      @param params The parameters for the operator. 
      <ul>
      <li>First parameter: 
      <ul>
      <li>0 = offspring is created on the line between the parents. 
      <li>1 = offspring is created in the hypercube defined by the 
      two parents (one weight per entry in realpos).
      </ul>
      <li>Second parameter: The number of offspring.
      </ul>
  */
  public static NumericalGenome[] crossover2(NumericalGenome parent1, NumericalGenome parent2, double[] params) 
    {
      RealNumericalGenome[] res;
      int i;
      res = new RealNumericalGenome[(int)params[1]];

      for (i=0; i<res.length; i++) {
	res[i] = (RealNumericalGenome)crossover(parent1, parent2, params);
      }
      return res;
    }


  /** Produce an array offspring from N parents.
      @param parents The parents.
      @param params The parameters for the operator. 
      <ul>
      <li>First parameter: 
      <ul>
      <li>0 = offspring is created on the line between the parents. 
      <li>1 = offspring is created in the hypercube defined by the 
      two parents (one weight per entry in realpos).
      </ul>
      <li>Second parameter: The number of offspring.
      </ul>
  */
  public static NumericalGenome[] crossover2(NumericalGenome[] parents, double[] params) 
    {
      RealNumericalGenome[] res;
      int i;
      res = new RealNumericalGenome[(int)params[1]];

      for (i=0; i<res.length; i++) {
	res[i] = (RealNumericalGenome)crossover(parents, params);
      }
      return res;
    }

}
